package com.hk.service.order.impl;

import com.hk.commons.*;
import com.hk.commons.enm.OrderMonitorEvent;
import com.hk.commons.entity.order.OrderInfo;
import com.hk.commons.entity.order.OrderMonitor;
import com.hk.dao.base.impl.BaseServiceImpl;
import com.hk.service.order.IOrderInfo;
import com.hk.service.order.IOrderMonitor;
import com.hk.service.product.IProductInfo;
import com.hk.service.sys.ISysUser;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.orm.hibernate4.HibernateOptimisticLockingFailureException;
import org.springframework.stereotype.Service;

import java.util.List;

/**
 * Created by Antinomy on 17/2/20.
 */
@Service
public class IOrderMonitorImpl extends BaseServiceImpl<OrderMonitor> implements
        IOrderMonitor<OrderMonitor> {

    private Logger logger = LoggerFactory.getLogger(IOrderMonitorImpl.class);

    @Autowired
    private IOrderInfo orderInfoService;

    @Autowired
    public ISysUser userService;

    @Autowired
    private IProductInfo productService;

    @Override
    public OrderMonitor findById(long id) {
        return getById(id);
    }

    @Override
    public OrderMonitor findByOrderId(long orderId) {
        HqlFilter hqlFilter = getOrderFilter(orderId);
        OrderMonitor orderMonitor = getByFilter(hqlFilter);

        return orderMonitor;
    }

    @Override
    public Long save(OrderMonitor orderMonitor) {
        super.save(orderMonitor);

        return orderMonitor.getId();
    }

    @Override
    public Long started(OrderMonitor orderMonitor) {
        return this.save(orderMonitor);
    }

    @Override
    public Long started(OrderInfo orderInfo) {
        OrderMonitor orderMonitor = new OrderMonitor();
        orderMonitor.setOrderId(orderInfo.getId());
        orderMonitor.setProductId(Long.valueOf(orderInfo.getProductId()));
        orderMonitor.setUserId(Long.valueOf(orderInfo.getUserId()));

        return this.save(orderMonitor);
    }

    @Override
    public void cancel(long orderId, String result) {
        OrderMonitorEvent status = OrderMonitorEvent.CANCEL;
        storeNewEvent(orderId, status, result);
    }

    @Override
    public void refund(Long orderId, String result) {
        OrderMonitorEvent status = OrderMonitorEvent.REFUND;
        storeNewEvent(orderId, status, result);

//        OrderInfo orderInDB = orderInfoService.findById(orderId);
//        if(orderInDB == null) {
//            return;
//        }
//        fallbackProductSellAmount(orderInDB);
    }

    @Override
    public void preAuthStarted(long orderId) {
        OrderMonitorEvent status = OrderMonitorEvent.PRE_AUTH_STARTED;
        storeNewEvent(orderId, status);
    }

    @Override
    public void preAuthFailed(long orderId, String result) {
        OrderMonitorEvent status = OrderMonitorEvent.PRE_AUTH_FAILED;
        storeNewEvent(orderId, status, result);
    }

    @Override
    public void preAuthFinish(long orderId) {
        OrderMonitorEvent status = OrderMonitorEvent.PRE_AUTH_FINISH;
        storeNewEvent(orderId, status);
    }

    @Override
    public void updateProductStarted(long orderId) {
        OrderMonitorEvent status = OrderMonitorEvent.UPDATE_PRODUCT_STARTED;
        storeNewEvent(orderId, status);
    }

    @Override
    public void updateProductFailed(long orderId, String result) {
        OrderMonitorEvent status = OrderMonitorEvent.UPDATE_PRODUCT_FAILED;
        storeNewEvent(orderId, status, result);
    }

    @Override
    public void updateProductFinish(long orderId) {
        OrderMonitorEvent status = OrderMonitorEvent.UPDATE_PRODUCT_FINISH;
        storeNewEvent(orderId, status);
    }

    @Override
    public void success(long orderId) {
        OrderMonitorEvent status = OrderMonitorEvent.SUCCESS;
        storeNewEvent(orderId, status);

        OrderInfo orderInDB = orderInfoService.findById(orderId);
        if(orderInDB == null) {
            return;
        }

        addToSmsTask(orderInDB);
    }

    @Override
    public List<OrderMonitor> findByStatus(OrderMonitorEvent status) {
        HqlFilter hqlFilter = new HqlFilter();
        hqlFilter.addEQFilter("status", status);

        List<OrderMonitor> result = super.findByFilter(hqlFilter);
        return result;
    }

    private HqlFilter getOrderFilter(long orderId) {
        HqlFilter hqlFilter = new HqlFilter();
        hqlFilter.addEQFilter("orderId", orderId);
        return hqlFilter;
    }

    private void storeNewEvent(long orderId, OrderMonitorEvent event) {
        storeNewEvent(orderId, event, null);
    }

    private void storeNewEvent(long orderId, OrderMonitorEvent event, String result) {
        HqlFilter hqlFilter = getOrderFilter(orderId);
        OrderMonitor orderMonitor = getByFilter(hqlFilter);

        OrderMonitor newEvent = new OrderMonitor();
        newEvent.setEvent(event);
        newEvent.setOrderId(orderMonitor.getOrderId());
        newEvent.setProductId(orderMonitor.getProductId());
        newEvent.setUserId(orderMonitor.getUserId());
        newEvent.setResult(result);

        this.save(newEvent);
    }

    private void addToSmsTask(OrderInfo orderInDB) {
        // 　add by Sam 2016/08/26　把支付成功已成功的下单的记录写入缓存，task进行信息推送
        try {
            if (ConstantOrderStatus.PAY_STATUS_TRUE == orderInDB.getPayStatus()) {
                RedisCilent.listSet(CacheConstants.ORDER_SEND_SMS_PUSH, JsonUtils.toJson(orderInDB));
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void fallbackProductSellAmount(OrderInfo orderInDB) {
        try {
            productService.updAmountByPay(
                    orderInDB.getProductId(),
                    orderInDB.getSuccessAmount(),
                    false);

        } catch (HibernateOptimisticLockingFailureException ex) {
            logger.error(ex.getMessage()+" will try one more time !");

            //try again
            productService.updAmountByPay(
                    orderInDB.getProductId(),
                    orderInDB.getSuccessAmount(),
                    false);
        }

    }

}
